/**
 * @file bull_hal_drv_pin.c
 * @brief 
 * @author yejing (yejh@gongniu.cn)
 * @version 1.0
 * @date 2024-05-28
 * 
 * Copyright 2024-2025 GongNiu Inc. All Rights Reserved.
 * 
 */
#include "bull_hal_drv_pin.h"

#include "driver/gpio.h"
#include "esp_attr.h"


static BULL_PIN_DEV_MAP_T pinmap[ BULL_GPIO_NUM_MAX ] = { 0 };


static void IRAM_ATTR gpio_isr_handler(void* arg)
{
    BULL_PIN_DEV_MAP_T *p_pin_dev = (BULL_PIN_DEV_MAP_T*)arg;
    p_pin_dev->cb(arg);
}


/**
 * @brief 初始化 pin 脚
 * 
 * @param pin pin 引脚
 * @param mode 输入输出模式
 * @param irq_mode 中断触发模式
 * @param irq_cb 中断回调函数
 * @return int 
 */
int bull_hal_drv_pin_init( BULL_PIN_NAME_t pin, BULL_PIN_MODE_T mode, BULL_PIN_ACTIVE_T pin_active, BULL_IRQ_MODE_T irq_mode, BULL_PIN_IRQ_CB irq_cb )
{
    gpio_config_t io_conf;

    pinmap[ pin ].gpio = pin;

    //set as output mode
    switch (mode)
    {
        case BULL_PIN_DISABLE:
            io_conf.mode = GPIO_MODE_DISABLE;
            break;

        case BULL_PIN_INPUT:
            io_conf.mode = GPIO_MODE_INPUT;
            break;

        case BULL_PIN_OUTPUT:
            io_conf.mode = GPIO_MODE_OUTPUT;
            break;

        case BULL_PIN_OUTPUT_OD:
            io_conf.mode = GPIO_MODE_OUTPUT_OD;
            break;

        case BULL_PIN_INPUT_OUTPUT_OD:
            io_conf.mode = GPIO_MODE_INPUT_OUTPUT_OD;
            break;

        case BULL_PIN_INPUT_OUTPUT:
            io_conf.mode = GPIO_MODE_INPUT_OUTPUT;
            break;

        default:
            break;
    }

    //bit mask of the pins that you want to set,e.g.GPIO18/19
    io_conf.pin_bit_mask = ( 1ULL<<pin );

    //Pull up or down mode.
    if( pin_active == PIN_ACTIVE_LOW ){
        io_conf.pull_up_en = 0;
        io_conf.pull_down_en = 1;
    }else if( pin_active == PIN_ACTIVE_HIGH ){
        io_conf.pull_up_en = 1;
        io_conf.pull_down_en = 0;
    }else{
        io_conf.pull_up_en = 0;
        io_conf.pull_down_en = 0;
    }

    if(irq_mode == BULL_INTR_DISABLE){

        io_conf.intr_type = GPIO_INTR_DISABLE;
        gpio_config( &io_conf );
    }else{

        pinmap[ pin ].cb = irq_cb;
        switch ( irq_mode )
        {
            case BULL_INTR_POSEDGE:
                io_conf.intr_type = GPIO_INTR_POSEDGE;
                break;

            case BULL_INTR_NEGEDGE:
                io_conf.intr_type = GPIO_INTR_NEGEDGE;
                break;

            case BULL_INTR_ANYEDGE:
                io_conf.intr_type = GPIO_INTR_ANYEDGE;
                break;

            case BULL_INTR_LOW_LEVEL:
                io_conf.intr_type = GPIO_INTR_LOW_LEVEL;
                break;

            case BULL_INTR_HIGH_LEVEL:
                io_conf.intr_type = GPIO_INTR_HIGH_LEVEL;
                break;

            default:
                io_conf.intr_type = GPIO_INTR_ANYEDGE;
                break;
        }

        gpio_config( &io_conf );
        gpio_set_intr_type( pinmap[pin].gpio, io_conf.intr_type);
        gpio_install_isr_service(0);
        gpio_isr_handler_add(pin, gpio_isr_handler, &pinmap[pin]);
    }

    return OPRT_OS_ADAPTER_OK;
}



/**
 * @brief 复位pin的初始化
 * 
 * @param pin 
 * @return int 
 */
int bull_hal_drv_pin_deinit( BULL_PIN_NAME_t pin )
{
    return gpio_reset_pin( pin );
}


/**
 * @brief GPIO 写
 * 
 * @param pin 
 * @param level 
 * @return int 
 */
int bull_hal_drv_pin_write( BULL_PIN_NAME_t pin, BULL_PIN_LEVEL_t level )
{
    gpio_set_level( pin, level );

    return OPRT_OS_ADAPTER_OK;
}

/**
 * @brief GPIO 读
 * 
 * @param pin 
 * @return int 
 */
int bull_hal_drv_pin_read( BULL_PIN_NAME_t pin )
{
    return gpio_get_level(pin);
}

/**
 * @brief GPIO 翻转
 * 
 * @param pin 
 * @return int 
 */
int bull_hal_drv_pin_toggle( BULL_PIN_NAME_t pin )
{
    static uint32_t toggle_sta = 0;

    gpio_set_level(pin, toggle_sta);
    toggle_sta =!toggle_sta;

    return OPRT_OS_ADAPTER_OK;
}